#ifndef xpack_docker_heap
#define xpack_docker_heap
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::docker_heap::inc
#include"adapter/random_access.hpp"
#include"algo/heap_root.hpp"
#include"define/base_type.hpp"
#include"define/nullref.hpp"
#include"docker/page_array.hpp"
#include"dumb/disable_copy.hpp"
#include"dumb/erase_type.hpp"
#include"dumb/move.hpp"
#include"macro/xforward.hpp"
#include"macro/xexport.hpp"
#include"macro/xhand_over.hpp"
#include"macro/xstruct.hpp"
#include"macro/xunlikely.hpp"
#include"memop/cast.hpp"
#include"meta/has_constructor.hpp"
#include"utils/value_holder.hpp"
#define xheap_docker        ((docker &)(erased_docker &)m_array)
#pragma pop_macro("xuser")

namespace mixc::docker_heap {
    template<class heapable_t>
    concept can_heap = requires(heapable_t heap, typename heapable_t::item_t value, uxx index, uxx length){
        heap.clear();
        heap.push(value);
        value = inc::move(heap.pop()->value());
        value = inc::move(heap[index]);
        length = heap->length;
    };

    template<class item_t>
    using heap_docker = inc::page_array<item_t>;

    template<class itemx_t, template<class> class docker_t = heap_docker>
    requires(
        can_heap<
            docker_t<inc::erase_type<itemx_t>/*使用类型擦除*/>
        >
    )
    xstruct(
        xtmpl(heap, itemx_t, docker_t),
        xpubb(inc::disable_copy),
        xpubb(inc::random_access<heap<itemx_t, docker_t>, itemx_t>),
        xprif(m_array, docker_t<inc::erase_type<itemx_t>>),
        xasso(itemx_t)
    )
        using item_t        = itemx_t;
        using erase_type    = inc::erase_type<item_t>;
        using erased_docker = docker_t<inc::erase_type<item_t>>;
        using docker        = docker_t<item_t>;
    
    public:
        xprops()
            xpubgetx(root, item_t &){
                xr{
                    xunlikely(xthe.m_array->length == 0u){
                        return inc::nullref;
                    }
                    else{
                        return xheap_docker[0];
                    }
                }
            };

            xpubgetx(length, uxx){
                xr{ return xthe.m_array->length; }
            };

            xpubgetx(is_empty, bool){
                xr{ return xthe.m_array->length == 0u; }
            };
        $

        xprops_operator()

    public:
        template<class ... args_t>
        requires(sizeof...(args_t) != 0 and inc::has_constructor<erased_docker, void(args_t...)>)
        heap(args_t && ... args) : 
            m_array(xforward(args)...){
        }

        template<class ... args_t>
        requires(... and inc::has_constructor<item_t, void(args_t)>)
        heap(args_t && ... args) : 
            m_array(){

            if constexpr (sizeof...(args_t) != 0){
                this->push(xforward(args)...);
            }
        }

        xhand_over()

        ~heap(){
            this->clear();
        }

    public:
        void clear() {
            for(uxx i = 0, length = xthe->length; i < length; i++){
                xheap_docker[i].~item_t();
            }

            m_array.clear();
        }

        void push(item_t && value){
            this->push_core((item_t &&)value);
        }

        void push(item_t & value){
            this->push_core(value);
        }

        template<class first_t, class ... args_t>
        requires(
            sizeof...(args_t) != 0 and (
                inc::has_constructor<item_t, void(first_t &&)> and ... and 
                inc::has_constructor<item_t, void(args_t &&)>
            )
        )
        void push(first_t && first, args_t && ... list){
            this->push(xforward(first));
            this->push(xforward(list)...);
        }

        inc::value_holder<item_t> pop() {
            xunlikely(auto length = uxx(m_array->length); length == 0){
                return {};
            }
            else{
                inc::value_holder<item_t> result(
                    inc::heap_root::pop(xheap_docker, length)
                );

                m_array.pop();
                return result;
            }
        }

    private:
        template<class forward_item_t>
        void push_core(forward_item_t && value) {
            auto length             = uxx(m_array->length);
            auto temp               = inc::cast<erase_type>(value);
            m_array.push(temp);

            // 本次 push 默认内部拷贝构造
            inc::heap_root::push(xheap_docker, length, xforward(value));
        }

        friend inc::random_access<the_t, itemx_t>;

        item_t & random_get(uxx index) const {
            return xheap_docker[index];
        }
    $
}

namespace mixc::docker_heap::origin{
    using ::mixc::docker_heap::heap;
}

#undef  xheap_docker
#endif

xexport_space(mixc::docker_heap::origin)
